package xutil

import (
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

// Time2String  时间转换成字符串
func Time2String(time time.Time) string {
	time = time.Local()
	return time.Format("20060102150405")
}

// String2Time 字符串转换成时间
func String2Time(str string) (time.Time, error) {
	t, err := time.ParseInLocation("20060102150405", str, time.Local)
	if err == nil {
		t = CheckTime(t)
		return t, nil
	}
	t, err = time.ParseInLocation("2006-01-02 15:04:05", str, time.Local)
	if err == nil {
		t = CheckTime(t)
		return t, nil
	}
	t = CheckTime(t)
	return t, err
}

// Date2String 日期转字符串
func Date2String(time time.Time) string {
	time = time.Local()
	return time.Format("20060102")
}

// String2Date 字符串转换成日期
func String2Date(str string) (time.Time, error) {
	return time.ParseInLocation("20060102", str, time.Local)
}

// // TimeSince2019 从 2019 年到现在的Duration
// func TimeSince2019() time.Duration {
// 	return time.Now().Sub(t2019)
// }

// FileExists 文件是否存在
func FileExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

// WaitExit 挂起，等待退出
func WaitExit() {
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGHUP)

	sig := <-c
	fmt.Println("out sig:", sig)
}

// ShellRun linux平台 执行命令
func ShellRun(cmd string) error {
	sc := exec.Command("bash", "-c", cmd)
	return sc.Run()
}

// CmdRun win平台 执行命令
func CmdRun(cmd string) error {
	cc := exec.Command("cmd", "/c", "cls")
	return cc.Run()
}

func GetZeroTime() time.Time {
	zt, _ := time.ParseInLocation("2006-01-02 15:04:05", "0000-00-00 00:00:00", time.Local)
	return zt
}

// 获取当天零点时间
func GetStartOfToday() time.Time {
	timeStr := time.Now().Format("20060102")
	t, _ := time.ParseInLocation("20060102", timeStr, time.Local)
	return t
}

func GetStartOfToday1(tt string) time.Time {
	var t time.Time
	var timeStr string

	if tt == "utc" {
		timeStr = time.Now().UTC().Format("20060102")
		t, _ = time.ParseInLocation("20060102", timeStr, time.Local)
	} else {
		timeStr = time.Now().Format("20060102")
		t, _ = time.ParseInLocation("20060102", timeStr, time.Local)
	}

	return t
}

func GetStartOfDay(t time.Time) time.Time {
	timeStr := t.Format("20060102")
	tstart, _ := time.ParseInLocation("20060102", timeStr, time.Local)
	return tstart
}
func GetStartOfNextDay(t time.Time) time.Time {
	timeStr := t.Add(time.Hour * 24).Format("20060102")
	tstart, _ := time.ParseInLocation("20060102", timeStr, time.Local)
	return tstart
}

func GetStartOfMonth(t time.Time) time.Time {
	nowDay := t.Day()
	monthStart := t.AddDate(0, 0, (nowDay-1)*(-1))

	timeStr := monthStart.Format("20060102")
	st, _ := time.ParseInLocation("20060102", timeStr, time.Local)

	return st
}

func GetStartOfNextMonth(t time.Time) time.Time {
	var nextMonth time.Time
	for i := 1; i <= 31; i++ {
		nextMonth = time.Now().AddDate(0, 0, i)
		if nextMonth.Month() != t.Month() {
			break
		}
	}

	timeStr := nextMonth.Format("20060102")
	st, _ := time.ParseInLocation("20060102", timeStr, time.Local)

	return st
}

// 获取下周一零点时间
func GetStartOfNextWeek() time.Time {
	var nextWeek time.Time
	for i := 1; i <= 7; i++ {
		nextWeek = time.Now().AddDate(0, 0, i)
		if nextWeek.Weekday() == time.Monday {
			break
		}
	}

	timeStr := nextWeek.Format("20060102")
	t, _ := time.ParseInLocation("20060102", timeStr, time.Local)

	return t
}

var startDoubleWeekTime = time.Date(2024, 12, 2, 0, 0, 0, 0, time.Local)
var durDoubleWeek = time.Hour * 24 * 14

func GetStartOfDoubleWeek() time.Time {
	countWeek := time.Now().Sub(startDoubleWeekTime) / durDoubleWeek
	t := startDoubleWeekTime.Add(durDoubleWeek * countWeek)
	return t
}

func GetStartOfWeek() time.Time {
	var startOfWeek time.Time
	for i := 0; i < 7; i++ {
		startOfWeek = time.Now().AddDate(0, 0, i*(-1))
		if startOfWeek.Weekday() == time.Monday {
			break
		}
	}

	timeStr := startOfWeek.Format("20060102")
	t, _ := time.ParseInLocation("20060102", timeStr, time.Local)

	return t
}

func _getStartOfNextWeek(t time.Time) time.Time {
	var nextWeek time.Time
	for i := 1; i <= 7; i++ {
		nextWeek = t.AddDate(0, 0, i)
		if nextWeek.Weekday() == time.Monday {
			break
		}
	}

	timeStr := nextWeek.Format("20060102")
	tn, _ := time.ParseInLocation("20060102", timeStr, time.Local)

	return tn
}

func IsSameWeek(t1 time.Time, t2 time.Time) bool {
	t1nw := _getStartOfNextWeek(t1)
	t2nw := _getStartOfNextWeek(t2)

	if IsSameDay(t1nw, t2nw) {
		return true
	} else {
		return false
	}
}

func GetInitialTime() time.Time {
	timeStr := "20060102"
	t, _ := time.ParseInLocation("20060102", timeStr, time.Local)
	return t
}

func IsSameDay(t1 time.Time, t2 time.Time) bool {
	if t1.Year() == t2.Year() && t1.Month() == t2.Month() && t1.Day() == t2.Day() {
		return true
	} else {
		return false
	}
}

func SubDay(t1 time.Time, t2 time.Time) int32 {
	t1Start := GetStartOfDay(t1)
	t2Start := GetStartOfDay(t2)
	subDay := int32(t1Start.Sub(t2Start).Hours()) / 24
	return subDay
}

// MaxInt 最大数
func MaxInt(args ...int) int {
	max := args[0]

	for _, i := range args {
		if max < i {
			max = i
		}
	}
	return max
}

// MinInt 最小数
func MinInt(args ...int) int {
	min := args[0]
	for _, i := range args {
		if min > i {
			min = i
		}
	}
	return min
}

func CheckTime(t time.Time) time.Time {
	initialTime := GetInitialTime()
	if t.Before(initialTime) {
		return initialTime
	}
	return t
}

func Int2Str(val interface{}) string {
	return fmt.Sprintf("%d", val)
}
func Str2Int32(str string) int32 {
	n, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		fmt.Printf("!@!@!@!@ str2Int32 Error!!", err.Error(), str)
		return 0
	}
	return int32(n)
}
func Str2Int64(str string) int64 {
	n, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		fmt.Printf("!@!@!@!@ Str2Int64 Error!!", err.Error(), str)
		return 0
	}
	return n
}
func Str2UInt64(str string) (uint64, error) {
	n, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return 0, err
	}
	return uint64(n), nil
}
func GetRandomInt(s, e int) int {
	n := e - s
	return rand.Intn(n) + s
}
func GetRandomInt32(s, e int32) int32 {
	if s == e {
		return s
	}
	n := e - s
	return rand.Int31n(n) + s
}
func GetRandomInt64(s, e int64) int64 {
	n := e - s
	return rand.Int63n(n) + s
}
func GetRandomIntString() string {
	return Int2Str(rand.Int63() + 1)

}
func Time2StringRdsKey(time time.Time) string {
	time = time.Local()
	return time.Format("2006-01-02_15-04-05")
}

func String2TimeRdsKey(str string) (time.Time, error) {
	t, err := time.ParseInLocation("2006-01-02_15-04-05", str, time.Local)
	if err == nil {
		t = CheckTime(t)
		return t, nil
	}
	t = CheckTime(t)
	return t, err
}

var daysBefore = [...]int32{
	0,
	31,
	31 + 28,
	31 + 28 + 31,
	31 + 28 + 31 + 30,
	31 + 28 + 31 + 30 + 31,
	31 + 28 + 31 + 30 + 31 + 30,
	31 + 28 + 31 + 30 + 31 + 30 + 31,
	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
}

func daysIn(m time.Month, year int) int32 {
	if m == time.February && isLeap(year) {
		return 29
	}
	return daysBefore[m] - daysBefore[m-1]
}
func isLeap(year int) bool {
	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}

func GetCurMonthDays(t time.Time) int32 {
	return daysIn(t.Month(), t.Year())
}

func GetRandomValue(ary []int32) int32 {
	ct := int32(len(ary))
	rnd := GetRandomInt32(0, ct)
	return ary[rnd]
}
func GetRandomValue64(ary []int64) int64 {
	ct := int32(len(ary))
	rnd := GetRandomInt32(0, ct)
	return ary[rnd]
}

func GetRandomWeightArrayKey(weightAry []int32) int32 {
	if weightAry == nil {
		fmt.Printf("!@!@!@!@ GetWeightVal null,", weightAry)
		return 0
	}
	l := len(weightAry)
	if l == 0 {
		fmt.Printf("!@!@!@!@ GetWeightVal null,", weightAry)
		return 0
	}
	w := int32(0)
	for i := 0; i < l; i++ {
		w += weightAry[i]
	}
	if w == 0 {
		return 0
	}
	rnd := GetRandomInt32(0, w)
	w = int32(0)
	for i := 0; i < l; i++ {
		w += weightAry[i]
		if rnd < w {
			return int32(i)
		}
	}
	return 0
}

// Int642String  记秒值数字时间转换成字符串
func Int642String(timestampSeconds int64) string {
	// 转换为秒
	//seconds := timestamp
	// 使用Unix函数转换为time.Time
	time := time.Unix(timestampSeconds, 0)
	time = time.Local()
	return time.Format("2006-01-02 15:04:05")
}

// Time2String2  时间转换成字符串
func Time2String2(time time.Time) string {
	time = time.Local()
	return time.Format("2006-01-02 15:04:05")
}

func Int64ToTimeStr(val int64) string {
	time := time.Unix(val, 0)
	return time.Format("2006-01-02 15:04:05")
}

func Time2ActId(val int64) string {
	time := time.Unix(val, 0)
	return time.Format("20060102")
}
func Time2ActIdInt32(val int64) int32 {
	time := time.Unix(val, 0)
	str := time.Format("20060102")
	return Str2Int32(str)
}

// Next 生成下一个随机数
func nextSeed(seed int32) int32 {
	return int32((1664525*int64(seed) + 1013904223) & 0x7fffffff)
}

func GetRandomBySeed(seed *int32, start, end int32) int32 {
	*seed = nextSeed(*seed)
	if start == end {
		return start
	} else if start > end {
		start, end = end, start
	}
	val := start + *seed%(end-start)
	return val
}
func GetRandomValueBySeed(seed *int32, ary []int32) int32 {
	ct := int32(len(ary))
	rnd := GetRandomBySeed(seed, 0, ct)
	return ary[rnd]
}
